package com.thoughtworks.impersonator.http.record;

import static org.mockito.Matchers.anyObject;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import java.net.SocketAddress;

import org.jboss.netty.bootstrap.ClientBootstrap;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.handler.codec.http.HttpHeaders;
import org.jboss.netty.handler.codec.http.HttpRequest;
import org.junit.Before;
import org.junit.Test;

import com.thoughtworks.impersonator.http.message.storage.HttpExchangeStorage;

public class ClientConnectionHandlerTest {

    private ClientBootstrap httpClient;
    private Channel serverChannel;
    private MessageEvent event;
    private HttpRequest httpRequest;
    private ClientConnectionHandler handler;

    @Before
    public void createObjects() {
        httpClient = mock(ClientBootstrap.class);
        event = mock(MessageEvent.class);
        httpRequest = mock(HttpRequest.class);
        handler = new ClientConnectionHandler(httpClient, mock(HttpExchangeStorage.class), "localhost", 9999);
    }

    @Test
    public void shouldAttachRequestToContextToBeProcessedByServerHandler() throws Exception {
        ChannelHandlerContext context = mock(ChannelHandlerContext.class);
        assumeChannelOpenWasCalled(handler);
        when(event.getMessage()).thenReturn(httpRequest);

        handler.messageReceived(context, event);

        verify(context).setAttachment(httpRequest);
    }

    @Test
    public void shouldProxyRequestToServer() throws Exception {
        assumeChannelOpenWasCalled(handler);
        when(event.getMessage()).thenReturn(httpRequest);

        handler.messageReceived(mock(ChannelHandlerContext.class), event);

        verify(serverChannel).write(httpRequest);
    }

    @Test
    public void shouldRewriteHostHeaderToServerAddress() throws Exception {
        assumeChannelOpenWasCalled(handler);
        when(event.getMessage()).thenReturn(httpRequest);

        handler.messageReceived(mock(ChannelHandlerContext.class), event);

        verify(httpRequest).setHeader(HttpHeaders.Names.HOST, "localhost");
    }

    private void assumeChannelOpenWasCalled(ClientConnectionHandler handler) throws Exception {
        serverChannel = mock(Channel.class);
        ChannelHandlerContext context = mock(ChannelHandlerContext.class);
        ChannelStateEvent event = mock(ChannelStateEvent.class);
        Channel channel = mock(Channel.class);
        ChannelFuture future = mock(ChannelFuture.class);
        ChannelPipeline channelPipeline = mock(ChannelPipeline.class);

        when(event.getChannel()).thenReturn(channel);
        when(httpClient.getPipeline()).thenReturn(channelPipeline);
        when(httpClient.connect((SocketAddress) anyObject())).thenReturn(future);
        when(future.getChannel()).thenReturn(serverChannel);

        handler.channelOpen(context, event);
    }
}
